package com.youlu.campus.service.recycle.service.impl;

import com.google.common.collect.Lists;
import com.mongodb.client.result.UpdateResult;
import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.common.utils.IdGeneratorUtils;
import com.youlu.campus.entity.SmsTemplate;
import com.youlu.campus.entity.WechatMerchantConfig;
import com.youlu.campus.entity.course.dto.GoodsOrderDTO;
import com.youlu.campus.entity.dto.sms.SmsBaseInfoDTO;
import com.youlu.campus.entity.recycle.dto.*;
import com.youlu.campus.entity.recycle.vo.RecycleOrderInfoVo;
import com.youlu.campus.service.course.WechatPayService;
import com.youlu.campus.service.recycle.convert.RecycleItemConvert;
import com.youlu.campus.service.recycle.service.RecycleItemInfoService;
import com.youlu.campus.service.recycle.service.RecycleOrderService;
import com.youlu.campus.entity.recycle.RecycleOrderInfo;
import com.youlu.campus.service.course.QueryWrapper;
import com.youlu.campus.service.sms.SmsServerService;
import com.youlu.campus.service.sms.SmsTemplateService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.lang3.tuple.Triple;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author : [dengbo]
 * @className : RecycleOrderServiceImpl
 * @description : [回收订单service]
 * @createTime : [2022/6/23 14:43]
 */
@Service
@Slf4j
public class RecycleOrderServiceImpl implements RecycleOrderService {
    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private SmsTemplateService smsTemplateService;

    @Autowired
    private SmsServerService smsServerService;

    @Autowired
    private WechatPayService wechatPayService;

    @Autowired
    private RecycleItemConvert recycleItemConvert;

    @Override
    public Page<RecycleOrderInfoVo> search(RecycleOrderSearchDTO dto) {
        QueryWrapper query = new QueryWrapper();
        if (StringUtils.isNotBlank(dto.getOrderNo())) {
            query.where("orderNo", dto.getOrderNo());
        }
        if (StringUtils.isNotBlank(dto.getOrderId())) {
            query.where("id", dto.getOrderId());
        }
        if(StringUtils.isNotBlank(dto.getStatus())){
            query.where("status", Integer.valueOf(dto.getStatus()));
        }
        query.addCriteria(Criteria.where("deleted").ne(true));
        long count = mongoTemplate.count(query, RecycleOrderInfo.class);
        query.with(Sort.by(Sort.Order.desc("id")));
        PageRequest pageRequest = PageRequest.of(dto.getPage() - 1, dto.getPageSize());
        List<RecycleOrderInfo> data = mongoTemplate.find(query.with(pageRequest), RecycleOrderInfo.class);
        return PageableExecutionUtils.getPage(recycleItemConvert.recycleOrderToVo(data), pageRequest, () -> count);
    }

    @Override
    public boolean verify(RecycleOrderVerifyDTO dto) {
        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(dto.getOrderId()));
        RecycleOrderInfo orderInfo = mongoTemplate.findOne(query, RecycleOrderInfo.class);
        if (orderInfo == null) {
            throw new BusinessException("回收订单不存在");
        }
        boolean pass = dto.getType() == 1;
        int status = pass ? 2 : 1;
        query.addCriteria(Criteria.where("status").is(0));
        Update update = new Update();
        update.set("verifyInfo", dto.getVerifyInfo());
        update.set("verifyImageUrls", dto.getVerifyImageUrls());
        update.set("status", status);
        UpdateResult result = mongoTemplate.updateFirst(query, update, RecycleOrderInfo.class);
        return result.getModifiedCount() > 0;
    }

    @Override
    public boolean cancel(RecycleOrderCancelDTO dto) {
        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(dto.getOrderId()));
        RecycleOrderInfo orderInfo = mongoTemplate.findOne(query, RecycleOrderInfo.class);
        if (orderInfo == null) {
            throw new BusinessException("回收订单不存在");
        }
        List<Integer> statusList = Lists.newArrayList(0, 1, 2);
        query.addCriteria(Criteria.where("status").in(statusList));
        Update update = new Update();
        update.set("status", 3);
        update.set("reason", dto.getReason());
        UpdateResult result = mongoTemplate.updateFirst(query, update, RecycleOrderInfo.class);
        return result.getModifiedCount() > 0;
    }

    @Override
    public boolean transfer(RecycleOrderTransferDTO req) {
        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(req.getOrderId()));
        RecycleOrderInfo order = mongoTemplate.findOne(query, RecycleOrderInfo.class);
        if (order == null) {
            throw new BusinessException("回收订单不存在");
        }
        if (!order.getStatus().equals(2)) {
            throw new BusinessException("核验通过状态才能打款");
        }
        if (order.getTotalPrice() < 30) {
            throw new BusinessException("金额小于0.3元不能转账");
        }
        SmsBaseInfoDTO dto = SmsBaseInfoDTO.builder().phone(req.getMobile()).code(req.getCode()).build();
        Pair<Boolean, String> result = smsServerService.checkVerifyCode(dto);
        if (!result.getLeft()) {
            throw new BusinessException(result.getRight());
        }
        // 获取商户信息
        WechatMerchantConfig merchantInfo = wechatPayService.getWechatMerchantConfigById(order.getMerchantId());
        Triple<Boolean, Map, String> re = wechatPayService.transfer(buildTransferInfo(order), merchantInfo);
        if (!re.getLeft()) {
            throw new BusinessException(re.getRight());
        }
        String paymentNo = re.getMiddle().get("payment_no").toString();
        query.addCriteria(Criteria.where("status").is(2));
        Update update = new Update();
        update.set("payInfo", re.getMiddle());
        update.set("status", 4);
        update.set("paymentNo", paymentNo);
        UpdateResult updateResult = mongoTemplate.updateFirst(query, update, RecycleOrderInfo.class);
        return updateResult.getModifiedCount() > 0;
    }

    public GoodsOrderDTO buildTransferInfo(RecycleOrderInfo orderInfo) {
        GoodsOrderDTO dto = new GoodsOrderDTO();
        dto.setOrderNo(orderInfo.getOrderNo());
        dto.setPrice(orderInfo.getTotalPrice());
        dto.setOpenId(orderInfo.getOpenId());
        dto.setUserName(orderInfo.getUserName());
        dto.setGoodsName(orderInfo.getItemName());
        dto.setAppId(orderInfo.getAppId());
        dto.setClientIp(orderInfo.getClientIp());
        return dto;
    }

    @Override
    public boolean sendMsg(RecycleSmsSendDTO req) {
        SmsTemplate smsTemplate = smsTemplateService.findBySmsTemplate("", req.getSign(), "code");
        if (Objects.isNull(smsTemplate) || StringUtils.isBlank(smsTemplate.getSign()) || Objects.isNull(smsTemplate.getTempalteId())) {
            throw new BusinessException("短信模版配置错误");
        }
        // 消息类型 0发送短信、非0发送发送语音
        SmsBaseInfoDTO.SmsType smsType = SmsBaseInfoDTO.SmsType.getTypeByValue(req.getVerifyCodeType());
        String templeteId = SmsBaseInfoDTO.SmsType.SMS.equals(smsType) ? String.valueOf(smsTemplate.getTempalteId()) : smsTemplate.getVoiceTempalteId();
        SmsBaseInfoDTO dto = SmsBaseInfoDTO.builder()
                .smsType(smsType)
                .phone(req.getMobile())
                .templateId(templeteId)
                .signName(smsTemplate.getSign())
                .build();
        // 发送消息
        Pair<Boolean, String> result = smsServerService.sendSmsMsg(dto);
        if (!result.getLeft()) {
            throw new BusinessException(result.getRight());
        }
        return true;
    }
}
